package xj.graph2d.app;

import static xj.app.BaseApplicationFrame.getResourceString;
import java.awt.Dimension;
import java.awt.geom.Rectangle2D;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.StringTokenizer;
import java.util.ArrayList;
import java.util.List;
import java.text.DecimalFormat;

import xj.graph2d.SimpleDrawView;
import xj.graph2d.DrawCanvas;
import xj.graph2d.View;

public class ZoomControl {

  public ZoomControl(DrawApp main) { 
    this.main = main; 
  }
  
  public JComponent[] makeComponents(boolean useZoomSlider) { 
    this.useZoomSlider = useZoomSlider;
    int n = (useZoomSlider ? 4 : 2);
    JComponent[] zoombar = new JComponent[n];
    int i = 0;
    JLabel zoomLabel = new JLabel("  " + getResourceString("Zoom.text") + "  ");
    zoombar[i++] = zoomLabel;

    if (useZoomSlider) { 
      zoomSlider = new JSlider(SwingConstants.HORIZONTAL, 10, 175, 100); 
      zoomSlider.setPreferredSize(new Dimension(100, 20));
      //zoomSlider.setPaintLabels(true);
      //zoomSlider.setPaintTicks(true);
      //zoomSlider.setPaintTrack(true);
      //zoomSlider.setSnapToTicks(true);
      zoomSlider.addChangeListener(new SliderListener());
      zoombar[i++] = zoomSlider;

      sliderValue = new JLabel("100%  ");
      zoombar[i++] = sliderValue;

      zoombar[i++] = new JSeparator(SwingConstants.VERTICAL);

    } else { 
      zoomBox = new JComboBox();
      String zlist = getResourceString("Zoom.list");
      StringTokenizer tk = new StringTokenizer(zlist);
      while (tk.hasMoreTokens()) {
	String token = tk.nextToken();
	zoomBox.addItem(token + "%");
	try { 
	  zoomSteps.add(Integer.parseInt(token));
	} catch (NumberFormatException e) {
	}
      }
      zoomBox.setSelectedItem("100%");
      zoomBox.setPrototypeDisplayValue("0000%");
      
      zoomBox.addItemListener(new ZoomListener());    
      zoombar[i++] = zoomBox;
    }

    return zoombar; 
  }

  public void setZoomDisplay(int zf) { 
    if (useZoomSlider) { 
      if (zoomSlider != null) { 
	zoomSlider.setValue(zf);
      }
    } else { 
      if (zoomBox != null) { 
	// convert to zoombox item index 
	int istep = findZoomStep(zf);
	zoomBox.setSelectedIndex(istep);
      }
    }
  }

  public void zoomFitWidth() { 
    View view = main.getView();
    DrawCanvas canvas = view.getCanvas();
    Dimension cd = canvas.getSize();
    Rectangle2D vr = view.getVirtualCanvasRectangle();
    float vw = (float) vr.getWidth(); 
    float cw = cd.width; 
    setZoomDisplay((int) ((cw / vw) * 100)); 
  }

  public void zoomFitHeight() { 
    View view = main.getView();
    DrawCanvas canvas = view.getCanvas();
    Dimension cd = canvas.getSize();
    Rectangle2D vr = view.getVirtualCanvasRectangle();
    float vh = (float) vr.getHeight(); 
    float ch = cd.height; 
    setZoomDisplay((int) ((ch / vh) * 100)); 
  }

  public void zoomFitWindow() { 
    View view = main.getView();
    DrawCanvas canvas = view.getCanvas();
    Dimension cd = canvas.getSize();
    Rectangle2D vr = view.getVirtualCanvasRectangle();
    float vw = (float) vr.getWidth(); 
    float vh = (float) vr.getHeight();
    float cw = cd.width; 
    float ch = cd.height; 
    int f1 = (int) ((cw / vw) * 100); 
    int f2 = (int) ((ch / vh) * 100); 
    setZoomDisplay(f1 <= f2 ? f1 : f2);
  }

  public void zoom(boolean up) { 
    SimpleDrawView view = main.getView();
    int sf = (int) (view.getScaleFactor() * 100);

    if (useZoomSlider) { 
      int sf1 = 100; 
      if (up) { 
	if (sf < 100) { 
	  if (sf < 75) { 
	    sf1 = sf + 25; 
	  }
	} else { 
	  sf1 = sf + 50; 
	}
	if (sf1 > 400) { 
	  sf1 = 400; 
	}
      } else { 
	if (sf <= 100) { 
	  sf1 = sf - 25; 
	} else { 
	  if (sf > 150) { 
	    sf1 = sf - 50; 
	  }
	}
	if (sf1 < 25) { 
	  sf1 = 25; 
	}
      }
      int v = 100;
      if (sf1 < 100) { 
	v = sf1; 
      } else if (sf1 > 100) { 
	v = (sf1 - 100) / 4 + 100; 
      }
      zoomSlider.setValue(v);
    } else { 
      // convert to zoombox item index 
      int step0 = findZoomStep(sf);
      int step1 = step0;
      if (up) { 
	if (step0 < (zoomSteps.size() - 1)) { 
	  step1 = step0 + 1;
	}
      } else { 
	if (step0 > 0) { 
	  step1 = step0 - 1;
	}
      }
      if (step1 != step0) { 
	zoomBox.setSelectedIndex(step1);
      }
    }
  }

  protected List<Integer> zoomSteps = new ArrayList<Integer>();

  protected int findZoomStep(int sf) { 
    int i100 = 0, imin = -1, min = -1;
    for (int i = 0; i < zoomSteps.size(); i++) { 
      int zstep = zoomSteps.get(i);
      int d = Math.abs(sf - zstep);
      if (d <= 5) { 
	return i;
      } else if (zstep == 100) {
	i100 = i; 
      } else { 
	if (min < 0 || 
	    d < min) { 
	  min = d; 
	  imin = i; 
	}
      }
    }
    if (imin > -1) { 
      return imin;
    }
    return i100; 
  }

  static protected DecimalFormat format = new DecimalFormat("####0");

  class SliderListener implements ChangeListener { 

    public void stateChanged(ChangeEvent e) {
      int v = zoomSlider.getValue();
      float f; 
      if (v == 100) { 
	f = 1; 
      } else if (v < 100) { 
	f = (float) v / 100f;
      } else {
	f = (float) ((v - 100) * 4 + 100) / 100f;
      }
      sliderValue.setText("" + format.format(f * 100) + "%  "); 
      SimpleDrawView view = main.getView();
      view.setScaleFactor(f);
      view.repaint();
    }

  }

  class ZoomListener implements ItemListener {

    public void itemStateChanged(ItemEvent event) {
      if (event.getStateChange() == ItemEvent.SELECTED) {
	Object item = event.getItem();
	if (item instanceof String) {
	  // each item is in the form of "nnn%"
	  String sitem = (String) item;
	  int i = sitem.indexOf('%');
	  if (i > 0) {
	    sitem = sitem.substring(0, i);
	  }
	  try {
	    float v = Float.parseFloat(sitem);
	    SimpleDrawView view = main.getView();
	    view.setScaleFactor(v / 100f);
	    view.repaint();
	  } catch (NumberFormatException e) {
	  }
	}
      }
    }

  }

  protected DrawApp main;
  protected boolean useZoomSlider = true; 

  protected JComboBox zoomBox;
  protected JSlider zoomSlider;
  protected JLabel sliderValue;

}